package com.cardlan.twoshowinonescreen;

import android.util.Log;

import java.io.FileDescriptor;

/**
 * Created by wuxd on 2019/1/10.
 */

public class CardLanStandardBus implements ICardOperator {

    static {
        // 标准常用
        System.loadLibrary("cardlan_StandardBus663");


    }

    private CardLanDevUtil mCardLanDevUtil;

    /**
     * the public Constructor .
     * the instance of {@link CardLanDevUtil} will be initialized
     */
    public CardLanStandardBus() {
        mCardLanDevUtil = new CardLanDevUtil();
    }

    @Override
    public CardLanDevUtil getCardLanDevUtil() {
        return mCardLanDevUtil;
    }

    public int callReadOne2FiveSectorDataFromCard(char VerifyFlag, byte[] key_array, char
            mode, byte[] returnArray) {
        return ReadOne2FiveSectorDataFromCard(VerifyFlag, key_array, mode, returnArray);
    }

    /**
     * open buzzer
     */
    public void callOpenBuzzer() {
        mCardLanDevUtil.openBuzzer();
    }

    /**
     * close buzzer
     */
    public void callCloseBuzzer() {
        mCardLanDevUtil.closeBuzzer();
    }

    /**
     * open RedLED
     */
    public void callOpenRedLED() {
        mCardLanDevUtil.openRedLED();
    }

    /**
     * close RedLED
     */
    public void callCloseRedLED() {
        mCardLanDevUtil.closeRedLED();
    }

    /**
     * open GreenLED
     */
    public void callOpenGreenLED() {
        mCardLanDevUtil.openGreenLED();
    }

    /**
     * close GreenLED
     */
    public void callCloseGreenLED() {
        mCardLanDevUtil.closeGreenLED();
    }

    /**
     * init the device.
     *
     * @return int if return value equal {@link DeviceCardConfig#INIT_DEVICE_STATUS_SUCCESS}, it
     * means init devcie success, else not.
     */
    public int callInitDev() {
        return InitDev();
    }

    /**
     * stop search card
     */
    public void callCardHalt() {
        CardHalt();
    }

    /**
     * card reset
     *
     * @param CardSn array for saving card serial number.
     * @return int if return value equal {@link DeviceCardConfig#CARD_RESET_STATUS_MONE_SUCCESS
     * } it means mifare1 card , else equal {@link DeviceCardConfig#CARD_RESET_STATUS_CPU_SUCCESS
     * } it means cpu card．
     */
    public int callCardReset(byte[] CardSn) {
        if (!ByteUtil.notNull(CardSn)) {
            Logs.d("the param is null");
            return -1;
        }
        if (CardSn.length < DeviceCardConfig.CARD_RESET_SIZE) {
            Logs.d("the param length is small than " + DeviceCardConfig.CARD_RESET_SIZE);
            return -2;
        }
        return CardReset(CardSn, 0);
    }

    /**
     * read data from mifare1 card
     *
     * @param SectorNo   　sector index
     * @param BlockNo    　area index
     * @param VerifyFlag verify flag.Suggest options(1)
     * @param key_array  　key byte array
     * @param mode       　key check mode. suggest options(0x0a(read)/0x0b(write)).
     * @return byte[] return byte array data
     */
    public byte[] callReadOneSectorDataFromCard(char SectorNo, char BlockNo, char
            VerifyFlag, byte[] key_array, char mode) {

        return ReadOneSectorDataFromCard(SectorNo, BlockNo, VerifyFlag, key_array, mode);
    }

    /**
     * write data array into mifare1 card
     *
     * @param SectorArray 　write data source array
     * @param SectorNo    　sector index
     * @param BlockNo     　area index
     * @param VerifyFlag  　verify flag.Suggest options(1)
     * @param key_array   　key byte array
     * @param mode        　key check mode. suggest options(0x0a(read)/0x0b(write)).
     * @return int return status, if the value equal
     * {@link DeviceCardConfig#MONE_CARD_WRITE_SUCCESS_STATUS} , it
     * means write data success.
     */
    public int callWriteOneSertorDataToCard(byte[] SectorArray, char SectorNo, char
            BlockNo, char VerifyFlag, byte[] key_array, char mode) {

        return WriteOneSertorDataToCard(SectorArray, SectorNo, BlockNo, VerifyFlag, key_array,
                mode);
    }

    /**
     * open serial . if you want san qr code , you must call this method.
     *
     * @param path     　file path,suggest ('/dev/ttyAMA4')
     * @param baudrate 　115200
     * @param flags    　suggest value 0
     * @return FileDescriptor file desc
     */
    public FileDescriptor callSerialOpen(String path, int baudrate, int flags) {
        return SerialOpen(path, baudrate, flags);
    }

    /**
     * close serial
     */
    public void callSerialClose() {
        SerialClose();
    }

    /**
     * invoke the native {@link #CpuSendCmd} method
     *
     * @param cmdArray     cmd byte array
     * @param receiveArray 　the array for saving result value
     * @return int status
     */
    public int callCpuSendCmd(byte[] cmdArray, byte[] receiveArray) {
        return CpuSendCmd(cmdArray, receiveArray);
    }

    ////////SPI

    /**
     * open spi
     *
     * @param path  spi path
     * @param flags flag
     * @return Object return spi obj
     */
    public Object callSPIOpen(String path, int flags) {
        return SPIOpen(path, flags);
    }

    /**
     * close current SPI
     */
    public void callSPIClose() {
        SPIClose();
    }

    /**
     * send spi cmd
     *
     * @param cmdBytes cmd byte array
     * @return byte[] spi call back data
     */
    public byte[] callSPITransfer(byte[] cmdBytes) {
        return SPITransfer(cmdBytes);
    }

    @Override
    public int callWrite(byte[] data, int len) {
        return write(data, len);
    }

    @Override
    public FileDescriptor callOpen(String path, int baudrate, int flags) {
        return open(path, baudrate, flags);
    }

    @Override
    public void callClose() {
        close();
    }

    @Override
    public int callJTBCardread(byte[] data) {
        return JTBCardread(data);
    }

    @Override
    public int callJTBNormalCardConsume(int money) {
        return JTBNormalCardConsume(money);
    }

    @Override
    public int callJTBCardLock() {
        return JTBCardLock();
    }

    @Override
    public int callYLCardread(byte[] data) {
        return YLCardread(data);
    }

    @Override
    public int callYLCardConsume(int type, int money) {
        return YLCardConsume(type, money);
    }

    @Override
    public int callYLCardHandleChannle1(int money, byte[] data) {
        return YLCardHandleChannle1(money, data);
    }

    @Override
    public void callQPBOCCalcMac(byte[] macKey, byte[] inData, int inLen, byte[] outMAC) {
        QPBOCCalcMac(macKey, inData, inLen, outMAC);
    }

    //==================================JNI part==========================================

    //JNI Part add by li bin

    /**
     * init the device.
     *
     * @return int if return value equal {@link DeviceCardConfig#INIT_DEVICE_STATUS_SUCCESS}, it
     * means init devcie success, else not.
     */
    private native static int InitDev();

    /**
     * card reset
     *
     * @param CardSn array for saving card serial number.
     * @return int if return value equal {@link DeviceCardConfig#CARD_RESET_STATUS_MONE_SUCCESS
     * } it means mifare1 card , else equal {@link DeviceCardConfig#CARD_RESET_STATUS_CPU_SUCCESS
     * } it means cpu card．
     */
    private native static int CardReset(byte[] CardSn, int type);

    /**
     * read data from mifare1 card
     *
     * @param SectorNo   　sector index
     * @param BlockNo    　area index
     * @param VerifyFlag verify flag.Suggest options(1)
     * @param key_array  　key byte array
     * @param mode       　key check mode. suggest options(0x0a(read)/0x0b(write)).
     * @return byte[] return byte array data
     */
    private native static byte[] ReadOneSectorDataFromCard(char SectorNo, char BlockNo, char
            VerifyFlag, byte[] key_array, char mode);

    /**
     * write data array into mifare1 card
     *
     * @param SectorArray 　write data source array
     * @param SectorNo    　sector index
     * @param BlockNo     　area index
     * @param VerifyFlag  　verify flag.Suggest options(1)
     * @param key_array   　key byte array
     * @param mode        　key check mode. suggest options(0x0a(read)/0x0b(write)).
     * @return int return status, if the value equal
     * {@link DeviceCardConfig#MONE_CARD_WRITE_SUCCESS_STATUS} , it
     * means write data success.
     */
    private native static int WriteOneSertorDataToCard(byte[] SectorArray, char SectorNo, char
            BlockNo, char VerifyFlag, byte[] key_array, char mode);

    /**
     * stop search card
     */
    private native void CardHalt();

    /**
     * read all byte array
     */
    private native int ReadOne2FiveSectorDataFromCard(char VerifyFlag, byte[] key_array, char
            mode, byte[] returnArray);


    ///==================================scan code =======================================

    /**
     * open serial . if you want san qr code , you must call this method.
     *
     * @param path     　file path,suggest ('/dev/ttyAMA4')
     * @param baudrate 　115200
     * @param flags    　suggest value 0
     * @return FileDescriptor file desc
     */
    private native static FileDescriptor SerialOpen(String path, int baudrate, int flags);

    /**
     * close serial
     */
    private native void SerialClose();


    ///=================================cpu card =======================================

    /**
     * send cpu card cmd
     *
     * @param cmdArray     　cmd array
     * @param receiveArray 　array for saving result value
     * @return int operation status
     */
    private native int CpuSendCmd(byte[] cmdArray, byte[] receiveArray);

    ///====================================SPI============================================

    /**
     * open spi
     * T
     *
     * @param path  spi path
     * @param flags flag
     * @return Object return spi obj
     */
    private native Object SPIOpen(String path, int flags);

    /**
     * close current SPI
     */
    private native void SPIClose();

    /**
     * send spi cmd
     *
     * @param spiBytes cmd byte array
     * @return byte[] spi call back data
     */
    private native byte[] SPITransfer(byte[] spiBytes);


    /**
     * DES card key , the key byte array is your data source, the data byte array is your key
     * byte array. this method only used for mifare1 card.
     *
     * @param keyArray  　source byte array
     * @param dataArray 　key byte array
     * @return byte[] return the des result array,the array length is
     * {@link DeviceCardConfig#DES_OUT_ARRAY_LENGTH}
     */
    public byte[] callDesCard(byte[] keyArray, byte[] dataArray) {
        byte[] outArray = new byte[DeviceCardConfig.DES_OUT_ARRAY_LENGTH];
        DesCard(keyArray, dataArray, outArray);
        return outArray;
    }

    /**
     * method for des cpu card
     *
     * @param desType  encrypt / decrypt
     * @param desMode  　ECB,CBC model
     * @param srcBytes 　data source
     * @param outBytes 　the result array for saving des value, this array length must equal the data
     *                 source length,or bigger than it.
     * @param keyBytes 　the key byte array , (support  8,16,24 bits)
     * @return char　return the des status
     */
    public char callRunDes(char desType, char desMode, byte[] srcBytes, byte[]
            outBytes, byte[] keyBytes) {
        char keyLength = ByteUtil.intToChar(keyBytes.length);
        char srcLength = ByteUtil.intToChar(srcBytes.length);
        return RunDes(desType, desMode, srcBytes, outBytes, srcBytes.length, keyBytes, keyLength);
//        return RunDes(desType, desMode, keyBytes, outBytes, keyBytes.length, srcBytes, srcLength);
    }

    /**
     * this method is used to calculation cpu card  mac .
     *
     * @param initIn   encrypt / decrypt, allow null
     * @param srcBytes data source
     * @param outBytes the result array for saving des value, this array length must equal
     *                 the data source length,or bigger than it.
     * @param keyBytes the key byte array , (support  8,16,24 bits)
     * @return char　return the des status
     */
    public char callMacAnyLength(byte[] initIn, byte[] srcBytes, byte[] outBytes, byte[] keyBytes) {
        char keyLength = ByteUtil.intToChar(keyBytes.length);
        return MacAnyLength(initIn, srcBytes, outBytes, srcBytes.length, keyBytes, keyLength);
    }

    /**
     * DES card key (native), the key byte array is your data source, the data byte array is your key
     * byte array. this method only used for mifare1 card.
     *
     * @param keyArray  　source byte array
     * @param dataArray 　key byte array
     * @param outArray  　the result array for saving des value
     * @return int return the des status
     */
    private native static int DesCard(byte[] keyArray, byte[] dataArray, byte[] outArray);

    /**
     * method for des cpu card
     *
     * @param desType        encrypt / decrypt
     * @param desMode        　ECB,CBC model
     * @param srcBytes       　data source
     * @param outBytes       　the result array for saving des value, this array length must equal the data
     *                       source length,or bigger than it.
     * @param srcBytesLength 　the length of data source.
     * @param keyBytes       　the key byte array , (support  8,16,24 bits)
     * @param keyLength      　the length of key byte array.
     * @return char　return the des status
     */
    private native static char RunDes(char desType, char desMode, byte[] srcBytes, byte[]
            outBytes, int srcBytesLength, byte[] keyBytes, char keyLength);

    /**
     * this method is used to calculation cpu card  mac .
     *
     * @param initInBytes    encrypt / decrypt, allow null
     * @param srcBytes       data source
     * @param outBytes       the result array for saving des value, this array length must equal
     *                       the data source length,or bigger than it.
     * @param srcBytesLength 　the length of data source.
     * @param keyBytes       the key byte array , (support  8,16,24 bits)
     * @param keyLength      　the length of key byte array.
     * @return char　return the des status
     */
    private native static char MacAnyLength(byte[] initInBytes, byte[] srcBytes, byte[]
            outBytes, int srcBytesLength, byte[] keyBytes, char keyLength);

    private native int read(byte[] data);

    private native int read(byte[] csn, byte[] data);

    private native int write(byte[] data, int len);

    private native FileDescriptor open(String path, int baudrate, int flags);

    private native void close();

    private native int JTBCardread(byte[] data);

    private native int JTBNormalCardConsume(int money);

    private native int JTBCardLock();

    public native int YLCardread(byte[] data);

    private native int YLCardConsume(int type, int money);

    public native int YLCardHandleChannle1(int money, byte[] data);

    public native void QPBOCCalcMac(byte[] macKey, byte[] inData, int inLen, byte[] outMAC);

    private native int DumpCardInfo();

    public native void QPBOCCalcMacYinshang(byte[] macKey, byte[] inData, int inLen, byte[] outMAC);

    public int callResetNfcChipSet() {
        return ResetNfcChipSet();
    }

    public int callCardResetToCpuInterface(byte[] data) {
        return CardResetToCpuInterface(data);
    }

    public int relayOpt(char index, char state){
        return relayopt(index, state);
    }

    public int getInputopt(){
        return getInputOpt();
    }

    // 返回值<=0 失败;     大于0 成功， 返回值减1 即为实际的 psam 卡座索引[0 - 5]
    // psamNum[6];  psamKeyIndex[2];
    //----------------------------------------------------------------------------------------
    public int callInitTuPsam(byte[] psamNum, byte[] psamKeyIndex) {
        Log.e("xxx", "callInitTuPsam");
        return InitTuPsam(psamNum, psamKeyIndex);//InitTuPsam(psamNum,psamKeyIndex)
    }

    // 返回值!=0 失败;     等于0 成功
    //----------------------------------------------------------------------------------------
    public int callInitPsam(int psamIndex, int baudRate) {
        Log.e("xxx", "callInitPsam");
        return InitPsam(psamIndex, baudRate);
    }

    // 返回值<=0 失败;     大于0 成功-->  获得应答数据的长度
    //----------------------------------------------------------------------------------------
    public int callPsamSendCommand(int psamIndex, byte[] cmdArray, int cmdLen, byte[] receiveArray) {
        Log.e("xxx", "callPsamSendCommand");
        return PsamSendCommand(psamIndex, cmdArray, cmdLen, receiveArray);
    }

    // 返回值<=0 失败;     大于0 成功， 返回值减1 即为实际的 psam 卡座索引[0 - 5]
    // psamNum[6];  psamKeyIndex[2];
    //----------------------------------------------------------------------------------------
    private native int InitTuPsam(byte[] psamNum, byte[] psamKeyIndex);

    // 返回值!=0 失败;     等于0 成功
    //----------------------------------------------------------------------------------------
    private native int InitPsam(int psamIndex, int baudRate);

    // 返回值<=0 失败;     大于0 成功-->  获得应答数据的长度
    //----------------------------------------------------------------------------------------
    private native int PsamSendCommand(int psamIndex, byte[] cmdArray, int cmdLen, byte[] receiveArray);


    private native int ResetNfcChipSet();


    private native int CardResetToCpuInterface(byte[] array);

    //int  mcu_cmd_read_and_write(unsigned char device,unsigned char action,unsigned char* send_data, unsigned char send_cmd_len[4], char* recv_data, unsigned char recv_cmd_len[4])
    private native int mcu_cmd_read_and_write();

    private native int relayopt(char index, char state);
    //2、状态输入
    //返回值(十进制)
    //0:两个无输入;
    //1;状态1有输入
    //16:状态2有输入;
    //17:状态1和状态2有输入;
    private native int getInputOpt();
}
